#include <winsock2.h>
#include "xdefs.hpp"
#include "xcontent.hpp"
#include "xlive.hpp"
#include "../xlln/debug-log.hpp"
#include "../xlln/xlln.hpp"

CRITICAL_SECTION xlive_critsec_xcontent;
// Key: enumerator handle (id).
// Value: Vector of ? that have already been returned for that enumerator.
std::map<HANDLE, void*> xlive_xcontent_enumerators;

// #5350
HRESULT WINAPI XLiveContentCreateAccessHandle(uint32_t user_index, XLIVE_CONTENT_INFO* content_info, uint32_t license_info_version, XLIVE_PROTECTED_BUFFER* protected_buffer, size_t protected_buffer_offset, HANDLE* content_access_handle, XOVERLAPPED* xoverlapped)
{
	TRACE_FX();
	if (user_index >= XLIVE_LOCAL_USER_COUNT) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User 0x%08x does not exist.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (xlive_local_users[user_index].signin_state == eXUserSigninState_NotSignedIn) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User %u is not signed in.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (!content_info) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (license_info_version != XLIVE_LICENSE_INFO_VERSION) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s (license_info_version != XLIVE_LICENSE_INFO_VERSION) (%u != %u).", __func__, license_info_version, XLIVE_LICENSE_INFO_VERSION);
		return E_INVALIDARG;
	}
	if (!protected_buffer) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s protected_buffer is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (!content_access_handle) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_access_handle is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (xoverlapped) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s xoverlapped is not NULL.", __func__);
		return E_NOTIMPL;
	}
	
	XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s TODO.", __func__);
	*content_access_handle = 0;
	return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
	return S_OK;
}

// #5351
HRESULT WINAPI XLiveContentInstallPackage(XLIVE_CONTENT_INFO* content_info, const wchar_t* cab_file_pathname, XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS* callback_install_params)
{
	TRACE_FX();
	if (!content_info) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (content_info->dwContentAPIVersion != XLIVE_CONTENT_API_VERSION) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info->dwContentAPIVersion (%u) != XLIVE_CONTENT_API_VERSION (%u).", __func__, content_info->dwContentAPIVersion, XLIVE_CONTENT_API_VERSION);
		return E_INVALIDARG;
	}
	if (content_info->dwContentType != XCONTENTTYPE_MARKETPLACE) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s (content_info->dwContentType != XCONTENTTYPE_MARKETPLACE) (%u != %u).", __func__, content_info->dwContentType, XCONTENTTYPE_MARKETPLACE);
		return E_INVALIDARG;
	}
	if (!cab_file_pathname) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s cab_file_pathname is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (callback_install_params) {
		if (callback_install_params->cbSize != sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V1) && callback_install_params->cbSize != sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V2)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->cbSize (%u) is not sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_(V1/V2)) (12/16).", __func__, callback_install_params->cbSize);
			return E_INVALIDARG;
		}
		if (!callback_install_params->pInstallCallback && callback_install_params->cbSize == sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V1)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->pInstallCallback is NULL.", __func__);
			return E_INVALIDARG;
		}
		if (!callback_install_params->pInstallCallback && !callback_install_params->pInstallCallbackEx && callback_install_params->cbSize == sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V2)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->pInstallCallback and callback_install_params->pInstallCallbackEx is NULL.", __func__);
			return E_INVALIDARG;
		}
	}
	
	XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s TODO.", __func__);
	return E_UNEXPECTED;
	return E_ACCESSDENIED;
	return S_OK;
}

// #5352
HRESULT WINAPI XLiveContentUninstall(XLIVE_CONTENT_INFO* content_info, XUID* uninstall_for_xuid, XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS* callback_install_params)
{
	TRACE_FX();
	if (!content_info) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (content_info->dwContentAPIVersion != XLIVE_CONTENT_API_VERSION) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info->dwContentAPIVersion (%u) != XLIVE_CONTENT_API_VERSION (%u).", __func__, content_info->dwContentAPIVersion, XLIVE_CONTENT_API_VERSION);
		return E_INVALIDARG;
	}
	if (content_info->dwContentType != XCONTENTTYPE_MARKETPLACE) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s (content_info->dwContentType != XCONTENTTYPE_MARKETPLACE) (%u != %u).", __func__, content_info->dwContentType, XCONTENTTYPE_MARKETPLACE);
		return E_INVALIDARG;
	}
	if (uninstall_for_xuid && !*uninstall_for_xuid) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s *uninstall_for_xuid is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (uninstall_for_xuid && !IsOnlineXUID(*uninstall_for_xuid)) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s uninstall_for_xuid is not an online account.", __func__);
		return E_INVALIDARG;
	}
	if (callback_install_params) {
		if (callback_install_params->cbSize != sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V1) && callback_install_params->cbSize != sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V2)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->cbSize (%u) is not sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_(V1/V2)) (12/16).", __func__, callback_install_params->cbSize);
			return E_INVALIDARG;
		}
		if (!callback_install_params->pInstallCallback && callback_install_params->cbSize == sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V1)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->pInstallCallback is NULL.", __func__);
			return E_INVALIDARG;
		}
		if (!callback_install_params->pInstallCallback && !callback_install_params->pInstallCallbackEx && callback_install_params->cbSize == sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V2)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->pInstallCallback and callback_install_params->pInstallCallbackEx is NULL.", __func__);
			return E_INVALIDARG;
		}
	}
	
	XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s TODO.", __func__);
	return E_UNEXPECTED;
	return E_ACCESSDENIED;
	return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
	return S_OK;
}

// #5354
HRESULT WINAPI XLiveContentVerifyInstalledPackage(XLIVE_CONTENT_INFO* content_info, XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS* callback_install_params)
{
	TRACE_FX();
	if (!content_info) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (content_info->dwContentAPIVersion != XLIVE_CONTENT_API_VERSION) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info->dwContentAPIVersion (%u) != XLIVE_CONTENT_API_VERSION (%u).", __func__, content_info->dwContentAPIVersion, XLIVE_CONTENT_API_VERSION);
		return E_INVALIDARG;
	}
	if (content_info->dwContentType != XCONTENTTYPE_MARKETPLACE) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s (content_info->dwContentType != XCONTENTTYPE_MARKETPLACE) (%u != %u).", __func__, content_info->dwContentType, XCONTENTTYPE_MARKETPLACE);
		return E_INVALIDARG;
	}
	if (callback_install_params) {
		if (callback_install_params->cbSize != sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V1) && callback_install_params->cbSize != sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V2)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->cbSize (%u) is not sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_(V1/V2)) (12/16).", __func__, callback_install_params->cbSize);
			return E_INVALIDARG;
		}
		if (!callback_install_params->pInstallCallback && callback_install_params->cbSize == sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V1)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->pInstallCallback is NULL.", __func__);
			return E_INVALIDARG;
		}
		if (!callback_install_params->pInstallCallback && !callback_install_params->pInstallCallbackEx && callback_install_params->cbSize == sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V2)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->pInstallCallback and callback_install_params->pInstallCallbackEx is NULL.", __func__);
			return E_INVALIDARG;
		}
	}
	
	XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s TODO.", __func__);
	return E_ABORT;
	return E_UNEXPECTED;
	return S_OK;
}

// #5355
HRESULT WINAPI XLiveContentGetPath(uint32_t user_index, XLIVE_CONTENT_INFO* content_info, wchar_t* result_content_pathname, size_t* result_content_pathname_size)
{
	TRACE_FX();
	if (user_index >= XLIVE_LOCAL_USER_COUNT) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User 0x%08x does not exist.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (xlive_local_users[user_index].signin_state == eXUserSigninState_NotSignedIn) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User %u is not signed in.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (!content_info) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (content_info->dwContentAPIVersion != XLIVE_CONTENT_API_VERSION) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info->dwContentAPIVersion (%u) != XLIVE_CONTENT_API_VERSION (%u).", __func__, content_info->dwContentAPIVersion, XLIVE_CONTENT_API_VERSION);
		return E_INVALIDARG;
	}
	if (!result_content_pathname_size) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_content_pathname_size is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (!*result_content_pathname_size && result_content_pathname) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_content_pathname is not NULL when *result_content_pathname_size is 0.", __func__);
		return E_INVALIDARG;
	}
	
	XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s TODO.", __func__);
	return E_UNEXPECTED;
	// i think path needs to end with / or backslash when this is implemented. Also note the different macros for potentially different paths XCONTENTTYPE_.
	return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
	return S_OK;
}

// #5356
HRESULT WINAPI XLiveContentGetDisplayName(uint32_t user_index, XLIVE_CONTENT_INFO* content_info, wchar_t* result_display_name, size_t* result_display_name_size)
{
	TRACE_FX();
	if (user_index >= XLIVE_LOCAL_USER_COUNT) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User 0x%08x does not exist.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (xlive_local_users[user_index].signin_state == eXUserSigninState_NotSignedIn) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User %u is not signed in.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (!content_info) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (content_info->dwContentAPIVersion != XLIVE_CONTENT_API_VERSION) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info->dwContentAPIVersion (%u) != XLIVE_CONTENT_API_VERSION (%u).", __func__, content_info->dwContentAPIVersion, XLIVE_CONTENT_API_VERSION);
		return E_INVALIDARG;
	}
	if (!result_display_name_size) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_display_name_size is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (!*result_display_name_size && result_display_name) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_display_name is not NULL when *result_display_name_size is 0.", __func__);
		return E_INVALIDARG;
	}
	
	XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s TODO.", __func__);
	return E_UNEXPECTED;
	return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
	return S_OK;
}

// #5357
HRESULT WINAPI XLiveContentGetThumbnail(uint32_t user_index, XLIVE_CONTENT_INFO* content_info, uint8_t* result_thumbnail, size_t* result_thumbnail_size)
{
	TRACE_FX();
	if (user_index >= XLIVE_LOCAL_USER_COUNT) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User 0x%08x does not exist.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (xlive_local_users[user_index].signin_state == eXUserSigninState_NotSignedIn) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User %u is not signed in.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (!content_info) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (content_info->dwContentAPIVersion != XLIVE_CONTENT_API_VERSION) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info->dwContentAPIVersion (%u) != XLIVE_CONTENT_API_VERSION (%u).", __func__, content_info->dwContentAPIVersion, XLIVE_CONTENT_API_VERSION);
		return E_INVALIDARG;
	}
	if (!result_thumbnail_size) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_thumbnail_size is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (!*result_thumbnail_size && result_thumbnail) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_thumbnail is not NULL when *result_thumbnail_size is 0.", __func__);
		return E_INVALIDARG;
	}
	
	XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s TODO.", __func__);
	return E_UNEXPECTED;
	return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
	return S_OK;
}

// #5358
HRESULT WINAPI XLiveContentInstallLicense(XLIVE_CONTENT_INFO* content_info, const wchar_t* license_file_pathname, XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS* callback_install_params)
{
	TRACE_FX();
	if (!content_info) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (content_info->dwContentAPIVersion != XLIVE_CONTENT_API_VERSION) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info->dwContentAPIVersion (%u) != XLIVE_CONTENT_API_VERSION (%u).", __func__, content_info->dwContentAPIVersion, XLIVE_CONTENT_API_VERSION);
		return E_INVALIDARG;
	}
	if (content_info->dwContentType != XCONTENTTYPE_MARKETPLACE) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s (content_info->dwContentType != XCONTENTTYPE_MARKETPLACE) (%u != %u).", __func__, content_info->dwContentType, XCONTENTTYPE_MARKETPLACE);
		return E_INVALIDARG;
	}
	if (!license_file_pathname) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s license_file_pathname is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (callback_install_params) {
		if (callback_install_params->cbSize != sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V1) && callback_install_params->cbSize != sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V2)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->cbSize (%u) is not sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_(V1/V2)) (12/16).", __func__, callback_install_params->cbSize);
			return E_INVALIDARG;
		}
		if (!callback_install_params->pInstallCallback && callback_install_params->cbSize == sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V1)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->pInstallCallback is NULL.", __func__);
			return E_INVALIDARG;
		}
		if (!callback_install_params->pInstallCallback && !callback_install_params->pInstallCallbackEx && callback_install_params->cbSize == sizeof(XLIVE_CONTENT_INSTALL_CALLBACK_PARAMS_V2)) {
			XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s callback_install_params->pInstallCallback and callback_install_params->pInstallCallbackEx is NULL.", __func__);
			return E_INVALIDARG;
		}
	}
	
	XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s TODO.", __func__);
	return E_UNEXPECTED;
	return E_ACCESSDENIED;
	return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
	return S_OK;
}

// #5360
uint32_t WINAPI XLiveContentCreateEnumerator(size_t item_count, XLIVE_CONTENT_RETRIEVAL_INFO* content_retrieval_info, size_t* result_buffer_size, HANDLE* enumerator_handle)
{
	TRACE_FX();
	if (!item_count) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s item_count is NULL.", __func__);
		return ERROR_INVALID_PARAMETER;
	}
	if (item_count > XMARKETPLACE_ASSET_MAX_ENUM_SIZE) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s item_count (%zu) is greater than XMARKETPLACE_ASSET_MAX_ENUM_SIZE (%u).", __func__, item_count, XMARKETPLACE_ASSET_MAX_ENUM_SIZE);
		return ERROR_INVALID_PARAMETER;
	}
	if (!result_buffer_size) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_buffer_size is NULL.", __func__);
		return ERROR_INVALID_PARAMETER;
	}
	if (!enumerator_handle) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s enumerator_handle is NULL.", __func__);
		return ERROR_INVALID_PARAMETER;
	}
	if (!content_retrieval_info) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_retrieval_info is NULL.", __func__);
		return ERROR_INVALID_PARAMETER;
	}
	if (content_retrieval_info->dwContentAPIVersion != XLIVE_CONTENT_API_VERSION) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_retrieval_info->dwContentAPIVersion (%u) != XLIVE_CONTENT_API_VERSION (%u).", __func__, content_retrieval_info->dwContentAPIVersion, XLIVE_CONTENT_API_VERSION);
		return ERROR_INVALID_PARAMETER;
	}
	if (content_retrieval_info->dwUserIndex >= XLIVE_LOCAL_USER_COUNT) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User 0x%08x does not exist.", __func__, content_retrieval_info->dwUserIndex);
		return ERROR_NO_SUCH_USER;
	}
	if (xlive_local_users[content_retrieval_info->dwUserIndex].signin_state == eXUserSigninState_NotSignedIn) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User %u is not signed in.", __func__, content_retrieval_info->dwUserIndex);
		return ERROR_NOT_LOGGED_ON;
	}
	if ((content_retrieval_info->dwRetrievalMask & XLIVE_CONTENT_FLAG_RETRIEVE_FOR_ALL_USERS) && (content_retrieval_info->dwRetrievalMask & XLIVE_CONTENT_FLAG_RETRIEVE_BY_XUID)) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s ((content_retrieval_info->dwRetrievalMask & XLIVE_CONTENT_FLAG_RETRIEVE_FOR_ALL_USERS) && (content_retrieval_info->dwRetrievalMask & XLIVE_CONTENT_FLAG_RETRIEVE_BY_XUID)).", __func__);
		return ERROR_INVALID_PARAMETER;
	}
	if (content_retrieval_info->dwContentType != XCONTENTTYPE_MARKETPLACE) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_retrieval_info->dwContentType (%u) is not XCONTENTTYPE_MARKETPLACE.", __func__, content_retrieval_info->dwContentType);
		return ERROR_INVALID_PARAMETER;
	}
	if (!(content_retrieval_info->dwRetrievalMask & XLIVE_CONTENT_FLAG_RETRIEVE_FOR_ALL_CONTENT_TYPES)) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s !(content_retrieval_info->dwRetrievalMask & XLIVE_CONTENT_FLAG_RETRIEVE_FOR_ALL_CONTENT_TYPES).", __func__);
		return ERROR_INVALID_PARAMETER;
	}
	if (!(content_retrieval_info->dwRetrievalMask & (XLIVE_CONTENT_FLAG_RETRIEVE_FOR_ALL_USERS | XLIVE_CONTENT_FLAG_RETRIEVE_BY_XUID))) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s !(content_retrieval_info->dwRetrievalMask & (XLIVE_CONTENT_FLAG_RETRIEVE_FOR_ALL_USERS | XLIVE_CONTENT_FLAG_RETRIEVE_BY_XUID)).", __func__);
		return ERROR_INVALID_PARAMETER;
	}
	
	*result_buffer_size = item_count * sizeof(XCONTENT_DATA);
	*enumerator_handle = CreateMutex(NULL, NULL, NULL);
	EnterCriticalSection(&xlive_critsec_xcontent);
	xlive_xcontent_enumerators[*enumerator_handle];
	LeaveCriticalSection(&xlive_critsec_xcontent);

	return ERROR_SUCCESS;
}

// #5361
HRESULT WINAPI XLiveContentRetrieveOffersByDate(uint32_t user_index, uint32_t offer_info_version, SYSTEMTIME* offers_start_date, XLIVE_OFFER_INFO* result_offer_infos, size_t* result_offer_info_count, XOVERLAPPED* xoverlapped)
{
	TRACE_FX();
	if (user_index >= XLIVE_LOCAL_USER_COUNT) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User 0x%08x does not exist.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (xlive_local_users[user_index].signin_state == eXUserSigninState_NotSignedIn) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User %u is not signed in.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (offer_info_version > XLIVE_OFFER_INFO_VERSION) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s (offer_info_version > XLIVE_OFFER_INFO_VERSION) (%u > %u).", __func__, offer_info_version, XLIVE_OFFER_INFO_VERSION);
		return E_INVALIDARG;
	}
	if (!result_offer_infos) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_offer_infos is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (!result_offer_info_count) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_offer_info_count is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (*result_offer_info_count != XLIVE_MAX_RETURNED_OFFER_INFO) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s (*result_offer_info_count != XLIVE_MAX_RETURNED_OFFER_INFO) (%zu != %u).", __func__, *result_offer_info_count, XLIVE_MAX_RETURNED_OFFER_INFO);
		return E_INVALIDARG;
	}
	
	uint32_t result = ERROR_FUNCTION_FAILED;
	XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s TODO.", __func__);
	
	if (xoverlapped) {
		//asynchronous
		
		xoverlapped->InternalLow = result;
		xoverlapped->InternalHigh = result;
		xoverlapped->dwExtendedError = result;
		
		Check_Overlapped(xoverlapped);
		
		return ERROR_IO_PENDING;
	}
	
	//synchronous
	return result;
}

// #5362
BOOL WINAPI XLiveMarketplaceDoesContentIdMatch(const uint8_t* content_id, const XLIVE_CONTENT_INFO* content_data)
{
	TRACE_FX();
	if (!content_id) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_id is NULL.", __func__);
		SetLastError(ERROR_INVALID_PARAMETER);
		return FALSE;
	}
	if (!content_data) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_data is NULL.", __func__);
		SetLastError(ERROR_INVALID_PARAMETER);
		return FALSE;
	}
	
	bool result = memcmp(content_id, &(content_data->abContentID), XLIVE_CONTENT_ID_SIZE) == 0;
	return result ? TRUE : FALSE;
}

// #5363
HRESULT WINAPI XLiveContentGetLicensePath(uint32_t user_index, XLIVE_CONTENT_INFO* content_info, wchar_t* result_license_pathname, size_t* result_license_pathname_size)
{
	TRACE_FX();
	if (user_index >= XLIVE_LOCAL_USER_COUNT) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User 0x%08x does not exist.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (xlive_local_users[user_index].signin_state == eXUserSigninState_NotSignedIn) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User %u is not signed in.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (!content_info) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (content_info->dwContentAPIVersion != XLIVE_CONTENT_API_VERSION) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s content_info->dwContentAPIVersion (%u) != XLIVE_CONTENT_API_VERSION (%u).", __func__, content_info->dwContentAPIVersion, XLIVE_CONTENT_API_VERSION);
		return E_INVALIDARG;
	}
	if (!result_license_pathname_size) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_license_pathname_size is NULL.", __func__);
		return E_INVALIDARG;
	}
	if (!*result_license_pathname_size && result_license_pathname) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_license_pathname is not NULL when *result_license_pathname_size is 0.", __func__);
		return E_INVALIDARG;
	}
	
	XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s TODO.", __func__);
	return E_UNEXPECTED;
	return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
	return S_OK;
}

// #5367
uint32_t WINAPI XContentGetMarketplaceCounts(uint32_t user_index, uint32_t content_categories, size_t result_content_offers_size, XOFFERING_CONTENTAVAILABLE_RESULT* result_content_offers, XOVERLAPPED* xoverlapped)
{
	TRACE_FX();
	if (user_index >= XLIVE_LOCAL_USER_COUNT) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User 0x%08x does not exist.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (xlive_local_users[user_index].signin_state == eXUserSigninState_NotSignedIn) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s User %u is not signed in.", __func__, user_index);
		return E_INVALIDARG;
	}
	if (!result_content_offers_size) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_content_offers_size is 0.", __func__);
		return E_INVALIDARG;
	}
	if (!result_content_offers) {
		XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s result_content_offers is NULL.", __func__);
		return E_INVALIDARG;
	}
	
	result_content_offers->dwNewOffers = 0;
	result_content_offers->dwTotalOffers = 0;
	
	uint32_t result = S_OK;
	XLLN_DEBUG_LOG(XLLN_LOG_CONTEXT_XLIVE | XLLN_LOG_LEVEL_ERROR, "%s TODO.", __func__);
	
	if (xoverlapped) {
		//asynchronous
		
		xoverlapped->InternalLow = result;
		xoverlapped->InternalHigh = result;
		xoverlapped->dwExtendedError = result;
		
		Check_Overlapped(xoverlapped);
		
		return ERROR_IO_PENDING;
	}
	
	//synchronous
	return result;
}
